package com.appspot.web2stanza;

import java.io.*;
import java.net.URL;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.security.MessageDigest;
import javax.servlet.http.*;

import com.google.appengine.api.urlfetch.ResponseTooLargeException;
import com.google.appengine.api.labs.taskqueue.*;
import static com.google.appengine.api.labs.taskqueue.TaskOptions.Builder.*;

public class MainServlet extends HttpServlet {

  public static final Logger log = Logger.getLogger(MainServlet.class.getName());

  public void init() {
  }

  public void doGet(HttpServletRequest req, HttpServletResponse res)
      throws IOException {

    // setup
    String url = req.getParameter("url");
    String lang = req.getLocale().getLanguage();
    String mode = "browser";
    String userAgent = req.getHeader("User-Agent");
    if (userAgent.contains("iPhone") ||
        userAgent.contains("iPod") ||
        userAgent.contains("iPad")) {
      mode = "iPhone";
    }
    String serverName = req.getServerName();
    String id = null;
    OutputStream os = null;

    MainServlet.log.info("URL => " + url);
    MainServlet.log.info("Lang => " + lang);
    MainServlet.log.info("User-Agent => " + userAgent);

    try {
      // validate params
      if (url == null || "".equals(url)) {
        throw new Exception("url is null");
      }

      // PDF redirect
      if (url.endsWith("pdf")) {
        if (mode.equals("iPhone")) {
          String redirectUrl = url.replaceAll("^.{4,5}:", "epub:");
          res.sendRedirect(redirectUrl);
        }
        return;
      }

      // fetch source html
      byte[] source = null;
      if (!url.contains(serverName)) {
        source = GAEFetch.fetch(new URL(url));
      } else {
        FileInputStream fis = new FileInputStream("index.html");
        byte[] buffer = new byte[1];
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        while (fis.read(buffer) > 0) {
          bo.write(buffer);
        }
        bo.close();
        fis.close();
        source = bo.toByteArray();
      }

      // generate digest for id with url and timestamp
      MessageDigest md = MessageDigest.getInstance("SHA");
      String systime = String.valueOf(System.currentTimeMillis());
      byte[] b = (url + systime).getBytes();
      md.update(b);
      byte[] digest = md.digest();
      StringBuffer sb = new StringBuffer();
      for (int i = 0; i < digest.length; i++) {
        sb.append(String.format("%02x", digest[i]));
      }
      id = sb.toString();

      // setup Web2Stanza
      Web2Stanza w2s = new Web2Stanza(id, url, lang);

      // construct epub file
      int epubSize = w2s.execute(source);

      // download epub file
      if (mode.equals("iPhone")) {
        res.sendRedirect("epub://" + serverName + "/download?id=" + id + "&length=" + String.valueOf(epubSize));
      } else {
        res.setContentType("application/epub+zip");
        res.setHeader("Content-Disposition", "filename=\"" + id + ".epub\"");
        res.setContentLength(epubSize);
        os = res.getOutputStream();
        w2s.download(os);
      }

    // error handling
    } catch (ResponseTooLargeException rtle) {
      MainServlet.log.warning("ResTooLargeException => " + rtle.getMessage());
      res.getWriter().println("This page is too large...");
      res.getWriter().println("Web2Stanza can't deal over 1MB page.(this is Google App Engine's restriction)");

    } catch (Exception e) {
      MainServlet.log.log(Level.SEVERE, "Stacktrace => ", e);
      res.sendRedirect("/error.jsp?url=" + url + "&error=" + e.toString());

    } finally {
      // cleaning
      Queue queue = QueueFactory.getDefaultQueue();
      queue.add(url("/cleaning").param("id", id).countdownMillis(300000));

      if (os != null) {
        os.close();
      }
    }

  }

  public void destroy() {
  }
}
